package com.rocky.component.elasticsearch.config;

import com.rocky.component.elasticsearch.annotation.scanner.RockyESModelScanner;
import com.rocky.component.elasticsearch.config.property.RockyElasticsearchProperty;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;

import java.util.List;

/**
 * @author rocky
 * date 2025-07-16
 * Description:
 */
@RequiredArgsConstructor
@EnableConfigurationProperties(value = RockyElasticsearchProperty.class)
public class RockyElasticsearchConfig {

    private final Logger logger = LoggerFactory.getLogger(RockyElasticsearchConfig.class);

    private final RockyElasticsearchProperty elasticsearchProperty;

    @Bean(destroyMethod = "close")
    public RestHighLevelClient restHighLevelClient() {
        logger.info("Rocky elasticsearch initializing start rockyElasticsearchConfig restHighLevelClient");

        List<String> hostList = elasticsearchProperty.getHost();
        String username = elasticsearchProperty.getUsername();
        String password = elasticsearchProperty.getPassword();
        Integer socketTimeout = elasticsearchProperty.getSocketTimeout();
        Integer connectTimeout = elasticsearchProperty.getConnectTimeout();
        Integer connectionRequestTimeout = elasticsearchProperty.getConnectionRequestTimeout();
        Integer maxConnectTotal = elasticsearchProperty.getMaxConnectTotal();
        Integer maxConnectPerRoute = elasticsearchProperty.getMaxConnectPerRoute();
        Long keepAliveStrategy = elasticsearchProperty.getKeepAliveStrategy();

        HttpHost[] httpHostArray = new HttpHost[hostList.size()];
        for (int index = 0; index < hostList.size(); index++) {
            httpHostArray[index] = HttpHost.create(hostList.get(index));
        }

        RestClientBuilder restClientBuilder = RestClient.builder(httpHostArray)
                .setRequestConfigCallback(requestConfigCallback -> {
                    requestConfigCallback.setSocketTimeout(socketTimeout);
                    requestConfigCallback.setConnectTimeout(connectTimeout);
                    requestConfigCallback.setConnectionRequestTimeout(connectionRequestTimeout);

                    return requestConfigCallback;
                })
                .setHttpClientConfigCallback(httpClientConfigCallback -> {
                    httpClientConfigCallback.disableAuthCaching();
                    httpClientConfigCallback.setMaxConnTotal(maxConnectTotal);
                    httpClientConfigCallback.setMaxConnPerRoute(maxConnectPerRoute);
                    if (keepAliveStrategy > 0) {
                        httpClientConfigCallback.setKeepAliveStrategy((response, context) -> keepAliveStrategy);
                    }

                    if (StringUtils.isNoneBlank(username, password)) {
                        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
                        credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));

                        httpClientConfigCallback.setDefaultCredentialsProvider(credentialsProvider);
                    }

                    return httpClientConfigCallback;
                });

        logger.info("Rocky elasticsearch initializing succeed rockyElasticsearchConfig restHighLevelClient");

        return new RestHighLevelClient(restClientBuilder);
    }

    @Bean
    public RockyESModelScanner rockyESModelScanner(RestHighLevelClient restHighLevelClient) {
        return new RockyESModelScanner(elasticsearchProperty, restHighLevelClient);
    }
}
